import json

from utils import log

import time


def load(path):
    """
    本函数从一个文件中载入数据,并转换为dict或者list
    path 是保存文件的路径
    r 只能读 （带r的文件必须先存在）
    """
    with open(path, 'r', encoding='utf-8') as f:
        s = f.read()
        log('load', s)
        return json.loads(s)


def save(data, path):
    """
    本函数，把一个dict或者list写入文件
    w+ 可读可写 如果文件存在 则覆盖整个文件不存在则创建  //要close 之后才算完成写入
    """
    s = json.dumps(data, indent=2, ensure_ascii=False)
    with open(path, 'w+', encoding='utf-8') as f:
        log('save', path, s, data)
        f.write(s)


class Model(object):
    @classmethod
    def new(cls, form):
        m = cls(form)
        m.save()
        return m

    def __repr__(self):
        """
        __repr__ 是一个魔法方法
        简单来说, 它的作用是得到类的 字符串表达 形式
        比如 print(u) 实际上是 print(u.__repr__())
        """
        classname = self.__class__.__name__
        # Python 字典(Dictionary) items() 函数以列表返回可遍历的(键, 值) 元组数组。
        properties = ['{}:({})'.format(k, v) for k, v in self.__dict__.items()]
        s = '\n'.join(properties)
        # 错误return '<{}\n{}>\n'.format(classname, s) 渲染html会编程标签
        return '< {}\n{} >\n'.format(classname, s)

    # @classmethod
    # def all(cls):
    #     """
    #     得到一个类的所有存储的实例
    #     """
    #     path = cls.db_path()
    #     models = load(path)
    #     # 因为todo子类重写new,不能再这么写了
    #     # ms = [cls.new(m) for m in models]
    #     # 修改后：cls(m)初始化，会根据Todo的__init__()属性，进行初始化对象
    #     ms = [cls(m) for m in models]
    #     return ms

    def save(self):
        """
        save用于把一个Model的实例保存到文件中;
        """
        # models = self.all()
        # log('models', models)
        #
        # models.append(self)
        # l = [m.__dict__ for m in models]
        # path = self.db_path()
        # save(l, path)
        """
        06models新增id属性
        """
        # 查找
        models = self.all()
        # log('models', models)
        # first_index = 0
        first_index = 1
        # 新增
        if self.__dict__.get('id') is None:
            if len(models) > 0:
                # 不是第一个数据
                self.id = models[-1].id + 1
            else:
                # 是第一个数据
                self.id = first_index
            models.append(self)
        # 更新
        else:
            index = -1
            for i, m in enumerate(models):
                if self.id == m.id:
                    index = i
                    break
            if index > -1:
                models[index] = self
        # 保存
        l = [m.__dict__ for m in models]
        path = self.db_path()
        save(l, path)

    @classmethod
    def db_path(cls):
        classname = cls.__name__
        # path = '{}.txt'.format(classname)
        path = 'data/{}.txt'.format(classname)
        return path

    @classmethod
    def find(cls, id):
        return cls.find_by(id=id)

    @classmethod
    def find_by(cls, **kwargs):
        """
        kwargs是只有一个元素的dict
        u = User.find_by(username='juran')
        """
        k, v = '', ''
        # key , value = 'username','juran'
        for key, value in kwargs.items():
            k, v = key, value
        all = cls.all()
        for m in all:
            if v == m.__dict__[k]:
                return m
        return None

    @classmethod
    def find_all(cls, **kwargs):
        """
        kwargs是只有一个元素的dict
        u = User.find_all(user_id='id')
        """
        k, v = '', ''
        # key , value = 'username','juran'
        for key, value in kwargs.items():
            k, v = key, value
        all = cls.all()
        data = []
        for m in all:
            if v == m.__dict__[k]:
                data.append(m)
        return data

    # def remove(self):
    #     models = self.all()
    #     if self.__dict__.get('id') is not None:
    #         index = -1
    #         for i, m in enumerate(models):
    #             if m.id == self.id:
    #                 index = i
    #                 break
    #         if index > -1:
    #             del models[index]
    #     # 保存
    #     l = [m.__dict__ for m in models]
    #     path = self.db_path()
    #     save(l, path)

    @classmethod
    def delete(cls, id):
        models = cls.all()
        index = -1
        for i, m in enumerate(models):
            if m.id == id:
                index = i
                break
        if index == -1:
            pass
        else:
            obj = models.pop(index)
            # 保存
            l = [m.__dict__ for m in models]
            path = cls.db_path()
            save(l, path)
            # 返回被删除的元素
            return obj

    def json(self):
        """
        返回当前 model 的字典表示
        # copy 会复制一份新数据并返回
        原因：json.dump()不能处理object,只能处理字典，字符串，数组，数字；所以，把object处理成为字典表示
        """
        d = self.__dict__.copy()
        return d

    @classmethod
    def _new_from_dict(cls, d):
        # 因为子元素(比如Todo,User,Weibo)的 __init__ 需要一个 form 参数
        # 所以这个给一个空字典
        m = cls({})
        for k, v in d.items():
            # setattr 是一个特殊的函数
            # 假设 k v 分别是 'name'  'gua'
            # 它相当于 m.name = 'gua'
            setattr(m, k, v)
        return m

    @classmethod
    def all(cls):
        """
        all 方法(类里面的函数叫方法)使用 load 函数得到所有的 models
        """
        path = cls.db_path()
        models = load(path)
        # 这里用了列表推导生成一个包含所有 实例 的 list
        # 因为这里是从 存储的数据文件 中加载所有的数据
        # 所以用 _new_from_dict 这个特殊的函数来初始化一个数据
        ms = [cls._new_from_dict(m) for m in models]
        return ms


# class User(Model):
#     def __init__(self, form):
#         self.id = form.get('id', None)
#         if self.id is not None:
#             self.id = int(self.id)
#         self.username = form.get('username', '')
#         self.password = form.get('password', '')
#         self.role = int(form.get('role', 10))
#
#     def is_admin(self):
#         return self.role == 1
#
#     def validate_login(self):
#         us = User.all()
#         for u in us:
#             if u.username == self.username and u.password == self.password:
#                 return True
#         return False
#
#     def validate_register(self):
#         return len(self.username) > 2 and len(self.password) > 2
#
#     def todos(self):
#         pass


class Message(Model):
    # 重写 Model的new(self,form)≈ Model的new() + User(Model)的__init__(self.form) 结合
    # def new(self, form):
    #     self.author = form.get('author', '')
    #     self.message = form.get('message', '')
    def __init__(self, form):
        self.author = form.get('author', '')
        self.message = form.get('message', '')


"""
buffet
1.Message重写 Model的new(self,form)≈ Model的new() + User(Model)的__init__(self.form) 结合
2.
"""
